package com.dylan.历史.java8.并发增强;

import org.junit.Test;

import java.util.Collections;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.LongAdder;
import java.util.function.Function;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * Created by Dylan on 2018/7/30.
 */
public class ConcurrentHashMap改进 {

    @Test
    public void test1() {
        ConcurrentHashMap<String, Long> map = new ConcurrentHashMap<>();
        String word = "asdf";
        /**
         * 统计单词的出现次数,通过循环+replace的方式实现
         * 注意:oldValue在初始时,有为null的可能
         */
        Long oldValue;
        Long newValue;
        do {
            oldValue = map.get(word);
            newValue = oldValue == null ? 1 : oldValue + 1;
        } while (!map.replace(word, oldValue, newValue));
    }

    @Test
    public void test2() {
        ConcurrentHashMap<String, LongAdder> map = new ConcurrentHashMap<>();
        String word = "asdf";
        /**
         * 使用AtomicLong或LongAdder来实现
         */
        map.putIfAbsent(word, new LongAdder());
        map.get(word).increment();
    }

    @Test
    public void test3() {
        ConcurrentHashMap<String, Long> map = new ConcurrentHashMap<>();
        String word = "asdf";
        /**
         * 使用原子更新方法
         */
        map.compute(word, (k, v) -> v == null ? 1 : v + 1);
    }

    @Test
    public void test4() {
        ConcurrentHashMap<String, LongAdder> map = new ConcurrentHashMap<>();
        String word = "asdf";
        /**
         * 使用原子更新方法
         * 与putIfAbsent方法不同.computeIfAbsent:与指定键相关联的当前（现有或计算）值，如果计算值为空，则为null
         */
        map.computeIfAbsent(word, k -> new LongAdder()).increment();
    }

    @Test
    public void test5() {
        ConcurrentHashMap<String, Long> map = new ConcurrentHashMap<>();
        String word = "asdf";
        /**
         * 如果指定的键尚未与值相关联或与null相关联，则将其与给定的非空值相关联。否则，将关联值替换为给定重映射函数的结果
         */
        map.merge(word, 2L, (existingValue, newValue) -> existingValue + newValue);
        map.merge(word, 12L, (existingValue, newValue) -> existingValue + newValue);
        System.out.println(map);
    }
    
    @Test
    public void test6() {
        Map<String, Long> wordMap = getWords().collect(Collectors.groupingBy(Function.<String>identity(), Collectors.counting()));
        ConcurrentHashMap<String, Long> map = new ConcurrentHashMap<>(wordMap);
        // 查询一个结果,对每个key应用一个函数,直到该函数返回一个非null的结果.value和entry同理.
        String word = map.searchKeys(Long.MAX_VALUE, k -> k.length() > 5 ? k : null);

        // 使用累加函数对value进行累加,key和entry同理.
        Long totalLength = map.reduceValues(Long.MAX_VALUE, (v1, v2) -> v1 + v2);

        // 对键值进行消费
        map.forEach((k, v) -> System.out.println(k + ":" + v));
        map.forEach(
                Long.MAX_VALUE, // 并行阀值
                (k, v) -> System.out.println(k + ":" + v) // 消费者
        );
        // 对键值先转换后消费
        map.forEachValue(Long.MAX_VALUE,
                v -> v > 2 ? v : null, // 转换器
                u -> System.out.println(u) // 消费者,消费转换器返回的非null值
        );

        // 期望原始类型结果时使用的reduce
        long totalLength2 = map.reduceValuesToLong(Long.MAX_VALUE, Long::longValue, 0, Long::sum);
    }
    
    private static Stream<String> getWords() {
        return Pattern.compile("[\\P{L}]+").splitAsStream("Ramesses VI was the fifth ruler of the Twentieth Dynasty of Egypt. He succeeded Ramesses V and reigned for about eight years in the mid-to-late 12th century BC before dying in his forties. Egypt lost control of its last strongholds in Canaan around the time of his reign. The pharaoh's power waned in Upper Egypt during his rule, while the high priest of Amun, Ramessesnakht, was turning Thebes in Upper Egypt into the religious capital and a second center of power on par with Pi-Ramesses in Lower Egypt, where the pharaoh resided. He was fond of cult statues of himself; more are known to portray him than any other Twentieth-Dynasty king after his father, Ramesses III. He usurped KV9, a tomb in the Valley of the Kings planned by and for Ramesses V, and had it enlarged and redecorated for himself. His mummy lay untouched for fewer than 20 years before pillagers damaged it.");
    }
}
